package com.dgut.Filter;

import com.dgut.service.AdminService;
import io.jsonwebtoken.*;
import io.jsonwebtoken.security.SignatureException;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import com.dgut.Config.AppProperties;
import com.dgut.util.JwtUtil;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import java.util.Optional;

import static java.util.stream.Collectors.toList;

@Component
@AllArgsConstructor
@Slf4j
public class JwtFilter extends OncePerRequestFilter {

    private final AppProperties appProperties;
    private final JwtUtil jwtUtil;

    @Override
    protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
                                    FilterChain filterChain) throws ServletException, IOException {
        System.out.println("============================================");
        System.out.println("JwtFilter");
        System.out.println(checkJWTToken(httpServletRequest));
        System.out.println("============================================");
        System.out.println();
        if(checkJWTToken(httpServletRequest)) {
            System.out.println("============================================");
            System.out.println("if(checkJWTToken)" );
            System.out.println("============================================");
            validateToken(httpServletRequest)
                    .filter(claims -> claims.get("authorities") != null)
                    .ifPresent(this::setupSpringAuthentication);
        }

        filterChain.doFilter(httpServletRequest, httpServletResponse);
    }

    /**
     * 验证Token是否有效
     * @param request
     * @return
     */
    private Optional<Claims> validateToken(HttpServletRequest request) {
        String jwtToken = request.getHeader(appProperties.getJwt().getHeader()).replace(
                appProperties.getJwt().getPrefix(), "");
        System.out.println("validateToken");
        try {
            System.out.println(Jwts.parserBuilder().setSigningKey(
                    jwtUtil.getKey()).build().parseClaimsJws(jwtToken).getBody());
            return Optional.of(Jwts.parserBuilder().setSigningKey(
                    jwtUtil.getKey()).build().parseClaimsJws(jwtToken).getBody());
        } catch (ExpiredJwtException | SignatureException |
                MalformedJwtException | UnsupportedJwtException | IllegalArgumentException e){
            log.error("Error parsing jwt {}", e.getLocalizedMessage());
            return  Optional.empty();
        }
    }

    /**
     * 构造 Authentication
     * @param claims
     */

    private void setupSpringAuthentication(Claims claims) {
        List<String> rawList = (List<String>) claims.get("authorities");

        val authorities = rawList.stream()
            .map(SimpleGrantedAuthority::new)
            .collect(toList());
        val authentication = new UsernamePasswordAuthenticationToken(claims.getSubject(), null,
                authorities);
        SecurityContextHolder.getContext().setAuthentication(authentication);
    }

    /**
     * 检查Jwt Token是否在HTTP报头中
     * @param request
     * @return
     */
    private boolean checkJWTToken(HttpServletRequest request) {
        String authenticationHeader = request.getHeader(appProperties.getJwt().getHeader());
        return authenticationHeader != null &&
                authenticationHeader.startsWith(appProperties.getJwt().getPrefix());
    }
}
